[#1063] Give back what the open reserved rather than what the configuration says by then, and ask for a restart when the cache size changes - #1066
Conversation
5d5b3e1 to
725ff9a
Compare
|
Rebased onto master now that #999 is merged ( Re-run green on the rebased head: |
725ff9a to
64f3cff
Compare
|
Rebased onto master once more, now that #994 is merged ( |
64f3cff to
bd9d9d1
Compare
|
Rebased onto master ( The restack carries no change of its own, so the suites are not re-run for it; |
maximthomas
left a comment
There was a problem hiding this comment.
praise: The quota now follows the cache that actually runs, instead of the configuration as it stands at close.
close()gives backreservedCacheSizein bothPDBStorageandJEStorage, andbuildConfigurationfinally honours the result ofacquireMemory(PDBStorage.java:1101,JEStorage.java:778).computeSize()readsserverContext.getMemoryQuota()rather than thememQuotafield, which is null until the first open.- The restart is declared in two places:
component-restartin both XMLs, andadminActionRequiredplus NOTE 630 in theConfigChangeResult.
issue (blocking): After the quota refuses the open's reservation, isConfigurationChangeAcceptable refuses every change to the backend entry, including a change that leaves the cache size alone.
opendj-server-legacy/src/main/java/org/opends/server/backends/pdb/PDBStorage.java:1556, opendj-server-legacy/src/main/java/org/opends/server/backends/jeb/JEStorage.java:1286
A refused reservation leaves reservedCacheSize == 0 while the storage stays open. From then on, newSize <= reservedCacheSize is false for every change. The check falls through to isMemoryAvailable(newSize), which asks for the same amount the quota just refused, and it adds no reason. ConfigurationHandler.replaceEntry asks every change listener on the entry, and nothing filters by property (ConfigurationHandler.java:620-627, ConfigChangeListenerAdaptor.java:339-345). So the following all fail with UNWILLING_TO_PERFORM and an empty reason:
- a
db-txn-no-syncchange; dsconfig set-backend-prop --set enabled:false;- the internal
ds-cfg-enabled: falsemodify thatTaskUtils.disableBackendmakes for an online import-ldif, rebuild-index or restore (TaskUtils.java:203-210).
BASE accepted all of these through newSize <= computeSize(config). Startup opens are not checked against the quota, so this state needs no config change. It comes up with a third PDB/JE backend at the default db-cache-percent 50. It also comes up with one JE backend whose db-cache-size is more than half the reservable pool, because validateDbCacheSize has already taken that size and kept it (#1067). A server restart gets back to the same state.
final long newSize = computeSize(newCfg);
final MemoryQuota quota = serverContext.getMemoryQuota();
// What does not grow past the size already configured asks the quota for nothing (BASE's rule);
// a growth is measured against what this storage holds, which is what the next open adds to.
return (newSize <= Math.max(reservedCacheSize, computeSize(config))
|| quota.isMemoryAvailable(newSize - reservedCacheSize))
&& checkConfigurationDirectories(newCfg, unacceptableReasons);aCacheSizeChangeIsAdmittedAgainstWhatTheStorageHolds keeps its outcome under this fix: with 64 MB held and 128 MB pending, 256 MB is refused and 192 MB admitted at 129 MB free.
Pin: repeat the open of aReservationTheQuotaRefusedIsNotGivenBackOnClose (32 MB free, a 64 MB cache), then assert that a db-txn-no-sync-only change is acceptable. Do this in both classes. The assertion is red at this head.
final PDBBackendCfg unchangedCache = createBackendCfg(SMALL_CACHE);
when(unchangedCache.isDBTxnNoSync()).thenReturn(true);
assertThat(storage.isConfigurationChangeAcceptable(unchangedCache, new ArrayList<LocalizableMessage>())).isTrue();suggestion (non-blocking): Admission is only asserted where the reservation equals the configured size. A refused open, an unchanged size and a shrink are never checked.
opendj-server-legacy/src/test/java/org/opends/server/backends/pdb/PDBStorageTest.java:638, :663, opendj-server-legacy/src/test/java/org/opends/server/backends/jeb/JEStorageTest.java:311, :334
The only calls to isConfigurationChangeAcceptable come after a granted 64 MB open, where reservedCacheSize == configuredCacheSize. Two mutants survive all six cases in both classes (found by reading; not run):
reservedCacheSizereplaced byconfiguredCacheSizein the admission line;- the
newSize <= reservedCacheSize ||short circuit dropped. In production that sends every shrink toSemaphore.tryAcquire(negative), which throwsIllegalArgumentException.
The blocking issue above ships green for the same reason.
Pin: after the refused open of aReservationTheQuotaRefusedIsNotGivenBackOnClose, assert that createBackendCfg(SMALL_CACHE + SMALL_CACHE / 4) is not acceptable. It is 16 MB above what is configured but 80 MB above what is held, which kills the reserved → configured swap. Then, after a granted open with the quota drained to 0 free, assert that createBackendCfg(SMALL_CACHE / 2) is acceptable. That kills the dropped short circuit.
suggestion (non-blocking): The percent arm of the restart note is not pinned. Every case sizes the cache with db-cache-size.
opendj-server-legacy/src/test/java/org/opends/server/backends/pdb/PDBStorageTest.java:616
Each applyConfigurationChange call in the class (:570, :586, :604, :624, :644) uses createBackendCfg(n * SMALL_CACHE). None goes through db-cache-percent, which is the shipped default (size 0, percent 50). The mutant newCacheSize = cfg.getDBCacheSize() at PDBStorage.java:1649 survives. On a percent-sized backend, that mutant makes every unrelated change set adminActionRequired and emit a note saying "X bytes … 0 bytes".
Pin: open with createBackendCfg(0) and getDBCachePercent() stubbed to 10. Assert that a db-txn-no-sync-only change at percent 10 leaves adminActionRequired() false, and that a change to percent 20 sets it and names memPercentToBytes(10) and memPercentToBytes(20).
suggestion (non-blocking): No test shows that the "opened with" baseline stays fixed across two changes.
opendj-server-legacy/src/test/java/org/opends/server/backends/pdb/PDBStorageTest.java:598
Every restart-note case applies a single change to a storage that was just opened. So the mutant configuredCacheSize = newCacheSize; after the addMessage survives. In production, that mutant turns open 64 → change 128 → change back to 64 into a restart note for a pool that still runs at 64.
final ConfigChangeResult back = storage.applyConfigurationChange(createBackendCfg(SMALL_CACHE));
assertThat(back.adminActionRequired()).isFalse();
assertThat(back.getMessages()).isEmpty();Pin: append this to aCacheSizeChangedWhileOpenAsksForARestart in both classes.
suggestion (non-blocking): The open guard of the restart note (db != null / env != null) is not pinned.
opendj-server-legacy/src/test/java/org/opends/server/backends/jeb/JEStorageTest.java:271, opendj-server-legacy/src/main/java/org/opends/server/backends/pdb/PDBStorage.java:1650, opendj-server-legacy/src/main/java/org/opends/server/backends/jeb/JEStorage.java:1380
Every case that calls applyConfigurationChange opens the storage first. The mutant that drops the guard survives both classes. On a storage that has been constructed but never opened, the listener is already registered, and the mutant sets adminActionRequired and names "0 bytes opened with". The effect is small: the apply then fails in registerMonitoredDirectory anyway, at BASE as at this head.
Pin: construct a storage without opening it, apply a config with a different cache size, and assert that adminActionRequired() is false and that NOTE 630 is not among the messages.
issue (non-blocking): NOTE 630 calls the opened-with size "reserved", including when the quota refused the reservation.
opendj-server-legacy/src/messages/org/opends/messages/backend.properties:1173, opendj-server-legacy/src/main/java/org/opends/server/backends/pdb/PDBStorage.java:1657, opendj-server-legacy/src/main/java/org/opends/server/backends/jeb/JEStorage.java:1387
Both callers pass configuredCacheSize into "the memory reserved for it … stay at the %d bytes". After a refused open the storage holds 0 bytes of the quota. A later cache change that the quota now admits therefore reports memory as reserved when none is. On the granted road the text is accurate.
NOTE_CONFIG_DB_CACHE_REQUIRES_RESTART_630=The change to the database cache of backend %s will not take effect \
until the backend is restarted: the cache the backend runs with stays at the %d bytes it was opened with until \
then, and the %d bytes now configured are reserved by the next openbd9d9d1 to
cba9d51
Compare
|
Thanks, all six taken. Round head: Blocking: a refused reservation refuses every change of the backend entry. Confirmed by reading. return (newSize <= Math.max(reservedCacheSize, computeSize(config))
|| quota.isMemoryAvailable(newSize - reservedCacheSize))
&& checkConfigurationDirectories(newCfg, unacceptableReasons);The comment above it now explains why a change that does not grow the size asks the quota for nothing. Admission pins. Percent arm. Fixed baseline across two changes. Your snippet is appended to Open guard. NOTE 630. Reworded to your text. The number and the arguments are unchanged: NOTE_CONFIG_DB_CACHE_REQUIRES_RESTART_630=The change to the database cache of backend %s will not take effect \
until the backend is restarted: the cache the backend runs with stays at the %d bytes it was opened with until \
then, and the %d bytes now configured are reserved by the next openRuns.
Each mutant is red on exactly the case(s) listed and green elsewhere. |
maximthomas
left a comment
There was a problem hiding this comment.
praise: A refused reservation no longer turns into a refused disable, and the quota now follows what the open actually took.
PDBStorage.isConfigurationChangeAcceptable:1559-1560/JEStorage.isConfigurationChangeAcceptable:1469-1470admit a change that does not grow the size pastMath.max(reservedCacheSize, computeSize(config))without asking the quota. Only a growth is measured against what the storage holds.aChangeWhichLeavesTheCacheSizeAloneIsAdmittedAfterARefusedReservationpins this in both classes.close()gives backreservedCacheSize(PDBStorage:1137,JEStorage:891), and a refusedacquireMemoryis now recorded as nothing held (PDBStorage:1101,JEStorage:842).
issue (non-blocking): For a JE backend sized by db-cache-percent, NOTE 630 prints the quota's estimate as "the cache the backend runs with", which is not the cache JE actually runs.
opendj-server-legacy/src/main/java/org/opends/server/backends/jeb/JEStorage.java:839, :1563-1571; opendj-server-legacy/src/messages/org/opends/messages/backend.properties:1173-1175; opendj-server-legacy/src/main/java/org/opends/server/backends/jeb/ConfigurableEnvironment.java:295
configuredCacheSize is memQuota.memPercentToBytes(percent), a percent of the quota's reservable pool ((e/π)² × Old Gen max). JE does not use that number. It sizes its own cache from je.maxMemoryPercent = db-cache-percent, which is a percent of Runtime.maxMemory. Take the default JE backend (size 0, percent 50) on -Xmx2g under G1: JE runs about 1 GiB, and a change to percent 40 reports that the cache "stays at the ~803,000,000 bytes it was opened with". On the percent arm the printed figure is always below JE's real cache. PDB builds its pool from configuredCacheSize (PDBStorage:1098), so PDB and a fixed-size JE backend report correctly. The quota arithmetic itself is consistent. For JE's percent arm, either name the configured percentage in the note, or describe the figure as the size the memory quota was asked for.
suggestion (non-blocking): No test covers the reservedCacheSize operand of the admission's Math.max.
opendj-server-legacy/src/main/java/org/opends/server/backends/pdb/PDBStorage.java:1559, opendj-server-legacy/src/main/java/org/opends/server/backends/jeb/JEStorage.java:1469
In every admission call in both classes, max(reserved, config) == config. The mutant newSize <= computeSize(config) || …, which is BASE's shape, therefore stays green. aCacheShrunkWhileOpenIsGivenBackAsItWasTaken is the one case with reserved > config, and it closes without asking for admission. Under that mutant, a sequence of open at 128 MB, shrink to 64 MB, then change to 96 MB calls isMemoryAvailable(-32 MB). That goes to Semaphore.tryAcquire(-32) (MemoryQuota:86, :103), which throws IllegalArgumentException out of the change listener.
@Test
public void aGrowthWithinWhatIsHeldAfterAShrinkAsksTheQuotaForNothing() throws Exception
{
closeAndRemove(storage);
storage = new PDBStorage(createBackendCfg(2 * SMALL_CACHE), serverContext);
storage.open(AccessMode.READ_WRITE);
storage.applyConfigurationChange(createBackendCfg(SMALL_CACHE));
assertThat(storage.isConfigurationChangeAcceptable(
createBackendCfg(SMALL_CACHE + SMALL_CACHE / 2), new ArrayList<LocalizableMessage>())).isTrue();
}Pin: the same case in JEStorageTest. Both are green at the head, and both throw IllegalArgumentException under the mutant.
suggestion (non-blocking): The restart note is asserted only after a growth, so a shrink while open could lose it with every case still green.
opendj-server-legacy/src/main/java/org/opends/server/backends/pdb/PDBStorage.java:1654, opendj-server-legacy/src/main/java/org/opends/server/backends/jeb/JEStorage.java:1564; opendj-server-legacy/src/test/java/org/opends/server/backends/pdb/PDBStorageTest.java:594, opendj-server-legacy/src/test/java/org/opends/server/backends/jeb/JEStorageTest.java:289
Every NOTE 630 assertion follows either a growth (SMALL_CACHE → 2 * SMALL_CACHE, percent 10 → 20) or a return to the opened size. The one shrink in each class discards its ConfigChangeResult. So the mutant newCacheSize > configuredCacheSize passes both classes. Under it, a live shrink returns SUCCESS with no admin action while the cache keeps its opened size.
// aCacheShrunkWhileOpenIsGivenBackAsItWasTaken
final ConfigChangeResult ccr = storage.applyConfigurationChange(createBackendCfg(SMALL_CACHE));
assertThat(ccr.adminActionRequired()).isTrue();
assertThat(ccr.getMessages().get(0).toString()).isEqualTo(
NOTE_CONFIG_DB_CACHE_REQUIRES_RESTART.get("PDBStorageTest", 2 * SMALL_CACHE, SMALL_CACHE).toString());Pin: the same in JEStorageTest, using BACKEND_ID. It is red under != → >.
suggestion (non-blocking): The move from the memQuota field to serverContext.getMemoryQuota() is not pinned for a storage that is not yet open.
opendj-server-legacy/src/main/java/org/opends/server/backends/pdb/PDBStorage.java:1558, :1564-1568; opendj-server-legacy/src/main/java/org/opends/server/backends/jeb/JEStorage.java:1468, :1474-1478
memQuota is null from the constructor, which already registers the listener, until buildConfiguration runs. Every admission call in the tests is on an open storage, where the field and serverContext.getMemoryQuota() are the same instance. The one unopened case uses a fixed SMALL_CACHE, so computeSize never reaches the quota. If either method went back to memQuota, both classes would stay green. In production, that version would throw a NullPointerException for a percent-sized backend (the default) changed between BackendImpl.configureBackend:196 and openBackend:204.
@Test
public void aStorageWhichIsNotOpenAdmitsAChangeOfItsCachePercent() throws Exception
{
final PDBStorage unopened = new PDBStorage(createBackendCfg(0L, 10), serverContext);
try
{
assertThat(unopened.isConfigurationChangeAcceptable(
createBackendCfg(0L, 20), new ArrayList<LocalizableMessage>())).isTrue();
}
finally
{
unopened.close();
}
}Pin: the same case in JEStorageTest. It is green at the head and throws NullPointerException if either method reads memQuota again.
nitpick (non-blocking): The javadoc of aStorageWhichIsNotOpenAsksForNoRestart says the change "is picked up by the open", but the apply fails before config = cfg.
opendj-server-legacy/src/test/java/org/opends/server/backends/pdb/PDBStorageTest.java:653, opendj-server-legacy/src/test/java/org/opends/server/backends/jeb/JEStorageTest.java:349-350
On a storage that was never opened, diskMonitor is still null, so registerMonitoredDirectory throws a NullPointerException. The catch turns it into an error result, and the next open uses the old configuration. The case still pins the open guard, which is what it is for. Reword the javadoc to say that a storage which is not open asks for no restart.
…han what the configuration says by then, and ask for a restart when the cache size changes PDBStorage and JEStorage reserved their cache size from the memory quota by reading config in buildConfiguration and released it by reading config again in close(). applyConfigurationChange swapped config in between without touching the quota or the cache, and neither db-cache-size nor db-cache-percent was marked as needing a restart, so a cache grown from 64 MB to 128 MB while the backend ran released 128 against 64 taken at the next disable - the one an online import makes included - and the quota believed 64 MB free that the server did not have, for the life of the JVM; a shrink left the difference reserved by nobody. The running cache was the old size throughout. Both storages now keep two numbers of their own: the cache size of the configuration they opened with, and of it what the quota granted - a tryAcquire it refused, which an open at startup is not checked against, reserved nothing and used to be released all the same. close() gives back the granted size. isConfigurationChangeAcceptable admits the difference to what is held rather than to config, which a change admitted but not yet applied has already moved to the new size. applyConfigurationChange on an open storage whose cache size the change moves sets adminActionRequired and says so (NOTE_CONFIG_DB_CACHE_REQUIRES_RESTART): PersistIt cannot resize a buffer pool once the database is open, and JEStorage has never resized its environment. The two properties are marked component-restart in both configuration XMLs, as db-directory is. PDBStorageTest and JEStorageTest, six cases each: the grow and the shrink give back what was taken, the change asks for a restart and names both sizes, a change which leaves the cache alone asks for nothing, admission is against what is held, and a reservation the quota refused is not given back.
…che past the configured size whatever the storage holds After an open the quota refused, a storage holds nothing of the quota, and the admission of the last commit measured every change against that nothing: newSize <= reservedCacheSize failed for any cache, and isMemoryAvailable(newSize) asked for the very amount the quota had just refused. Every change listener of the backend entry is asked about every change, whatever property it moves, so a change of db-txn-no-sync, a disable, and the disable TaskUtils.disableBackend makes for an online import-ldif, rebuild-index or restore were all refused with UNWILLING_TO_PERFORM and no reason. The state needs no change of configuration to reach: the server does not check the backends it opens at startup against the quota. A size which does not grow past the one configured now asks the quota for nothing again, as it did before this PR; a growth is still measured against what the storage holds, so the case of a change admitted but not applied keeps its outcome. NOTE 630 no longer calls the size the backend was opened with reserved, which after a refused open it is not. PDBStorageTest and JEStorageTest, five more cases each and one extended, each killing a mutant which survived both classes: a change which leaves the cache alone is admitted after a refused reservation, a growth after it is measured against nothing held, a shrink is admitted with the quota exhausted, a cache sized by percent asks for a restart only when the percent moves, a storage which is not open asks for none, and a change back to the size the storage opened with asks for nothing.
…s the memory quota counts it, and pin what the admission reads For a JE backend sized by db-cache-percent, NOTE 630 printed the quota's count of the cache - a percent of the quota's reservable pool, (e/pi)^2 of the old generation - as the cache the backend runs with. JE sizes its cache from je.maxMemoryPercent against the maximum heap, so the figure was always below the cache JE actually runs. The note now says that both figures are what the memory quota counts: the size the backend was opened with until the restart, and the size the next open reserves. PDB, which builds its pool from that count, and a JE backend of a fixed size read the same as before. PDBStorageTest and JEStorageTest, two more cases each and one extended, each killing a mutant which survived both classes: a growth within what is held after a shrink asks the quota for nothing (without the reserved operand of the admission's max, it asks the quota for a negative amount and the semaphore throws), a shrink while open asks for the restart as a growth does, and a storage which is not open admits a change of its cache percent (read from the field the open sets, the size is a NullPointerException there). The javadoc of the case of a storage which is not open no longer says the change is picked up by the open: the apply fails before it replaces the configuration.
cba9d51 to
d5fd0c1
Compare
|
Thanks for the review. Round 2 is d5fd0c1. The branch is first rebased onto master e333af0; the rebase is clean and issue - NOTE 630 on JE's percent arm. Confirmed:
"Reserved" stays off the first figure, as agreed in round 1, because after a refused open nothing is held. The ordinal stays at 630. The javadoc of suggestion - the suggestion - NOTE after a shrink. suggestion - quota of an unopened storage. nitpick - javadoc. It now says that a storage which is not open runs no cache to restart, and that a change of the cache size asks it for none. The "picked up by the open" wording is gone. Verification:
On the nitpick: the apply fails on an unopened storage because |
maximthomas
left a comment
There was a problem hiding this comment.
praise: Round 2's points are all answered in both storages, and each one is pinned.
- NOTE 630 now describes both figures as what the memory quota counts (
backend.properties:1173-1175). The javadoc ofJEStorage.configuredCacheSize(:736-738) explains why, on the percent arm, that figure differs from the cache JE actually runs. - Every round-2 test point now has a case in both classes.
aGrowthWithinWhatIsHeldAfterAShrinkAsksTheQuotaForNothing(PDBStorageTest:795,JEStorageTest:490) covers thereservedCacheSizeoperand of the admission'sMath.max.aStorageWhichIsNotOpenAdmitsAChangeOfItsCachePercent(PDBStorageTest:814,JEStorageTest:509) covers reading the quota throughserverContext.aCacheShrunkWhileOpenIsGivenBackAsItWasTakennow asserts NOTE 630 after a shrink (PDBStorageTest:599,JEStorageTest:294).
Summary
PDBStorageandJEStoragereserve their cache size from the server'sMemoryQuotawhen they open and release itwhen they close - both times by reading the configuration they hold at that moment. A change of
db-cache-sizeordb-cache-percenton a running backend swaps that configuration (applyConfigurationChangeends inconfig = cfg)without touching the quota or the cache, and neither property is marked as needing a restart. So the storage reserves
the old size and releases the new one at the next close - the disable an online
import-ldifmakes included - andthe quota drifts by the difference for the life of the JVM: a cache grown from 64 MB to 128 MB leaves the quota
believing 64 MB free that the server does not have; a shrink leaves 64 MB reserved by nobody. The running cache is
the old size throughout, and
dsconfigreports the change applied.Fixes #1063.
What changes
Both storages keep two numbers of their own instead of reading
configtwice:configuredCacheSize- the cache size of the configuration the storage opened with (for PDB, what the buffer poolwas built to);
reservedCacheSize- of it, what the quota granted.acquireMemoryis atryAcquire: refused, it reservesnothing, and the return value used to be ignored in both
buildConfigurations, so a close released a size thatwas never taken. That is reachable without any change - the server does not call
isConfigurationAcceptableforthe backends it opens at startup.
close()gives backreservedCacheSize.isConfigurationChangeAcceptableadmits a growth for the difference towhat is held rather than to
config: once a change has been admitted but not applied,computeSize(config)isalready the new size while the reservation is the old one, and a second change was admitted for a difference nobody
would reserve. A size which does not grow past the one configured asks the quota for nothing, as before
(
newSize <= max(reservedCacheSize, computeSize(config))): every change listener of the backend entry is asked aboutevery change, so after an open the quota refused - nothing held - a change of any other property, a disable, and the
disable
TaskUtils.disableBackendmakes for an online import, rebuild or restore would otherwise be refused.applyConfigurationChangeon an open storage whose cache size the change moves setsadminActionRequiredand addsNOTE_CONFIG_DB_CACHE_REQUIRES_RESTART(630), naming the size the backend was opened with and the one nowconfigured, both as the memory quota counts them: for a JE cache sized by
db-cache-percentthat is a percent of thequota's reservable pool, not the cache JE runs, which JE takes as a percent of the maximum heap.
db-cache-sizeanddb-cache-percentare markedcomponent-restartinPDBBackendConfiguration.xmlandJEBackendConfiguration.xml, asdb-directoryis in the same files, sodsconfigsays so too.Why a restart rather than a resize
PersistIt sizes its buffer pool when the database opens and has no way to resize it (
Persistit.setConfigurationrefuses a second configuration). JE could -
je.maxMemoryandje.maxMemoryPercentare mutable throughEnvironment.setMutableConfig- butJEStoragehas never resized its environment, and it is not alone: none of theJE properties the pluggable backend left without
requires-admin-actionis applied live since OPENDJ-1719 droppedthe
setMutableConfigroad of the old backend. Restoring that road for all of them is #1068; here the twostorages take the same shape, and the quota follows the cache that actually runs.
On master
The fix builds on the
close()of #999 - the quota given back once, and since its last round after the database hasclosed, in a
finally- and onJEStorageTest, which #999 introduces. #999 is merged; the branch sits on master,and the give-back of what the open reserved is the one inside that
finally. Rebased onto master0e039c6473for round 1 of the review: the one conflict was
JEStorageTest, where the replay cases of #1065 added theirimports and constants at the same places - a union, the test bodies merged on their own. #1070 (#1067) now asks
the quota in
validateDbCacheSizeinstead of taking from it, leaving the reservation to the storage, as here.Rebased onto master
e333af0c8ffor round 2 without a conflict (git range-diff:=for both earlier commits).Three commits: the fix, round 1 and round 2 on top.
Tests
PDBStorageTestandJEStorageTest, thirteen cases each, over a mockedServerContextwith a freshMemoryQuota:aCacheGrownWhileOpenIsGivenBackAsItWasTaken,aCacheShrunkWhileOpenIsGivenBackAsItWasTaken- the quota isback where it started after open, change, close; the shrink asks for the restart as a growth does, with both sizes;
aCacheSizeChangedWhileOpenAsksForARestart-adminActionRequired, the message id and both sizes; a changeback to the size opened with asks for nothing;
aChangeWhichLeavesTheCacheSizeAloneAsksForNothing- a change of another property asks for nothing, as before;aCacheSizedByPercentAsksForARestartOnlyWhenThePercentChanges-db-cache-size0 at percent 10: anotherproperty asks for nothing, percent 20 names
memPercentToBytes(10)andmemPercentToBytes(20);aStorageWhichIsNotOpenAsksForNoRestart- a storage constructed but never opened;aCacheSizeChangeIsAdmittedAgainstWhatTheStorageHolds- with 64 MB held and a change to 128 MB pending, 256 MB isrefused and 192 MB admitted at 129 MB free;
aChangeWhichLeavesTheCacheSizeAloneIsAdmittedAfterARefusedReservation- nothing held, 32 MB free, adb-txn-no-syncchange is admitted;aGrowthAfterARefusedReservationIsMeasuredAgainstNothingHeld- same state, 80 MB is refused;aShrinkIsAdmittedWithTheQuotaExhausted- 64 MB held, 0 free, 32 MB is admitted;aReservationTheQuotaRefusedIsNotGivenBackOnClose- 32 MB free, a 64 MB cache opens, and the close leaves 32 MB;aGrowthWithinWhatIsHeldAfterAShrinkAsksTheQuotaForNothing- opened at 128 MB, shrunk to 64 MB, 0 free: 96 MB isadmitted;
aStorageWhichIsNotOpenAdmitsAChangeOfItsCachePercent- a storage constructed but never opened admits percent10 → 20.
Five of the six were red on the head of #999 before the fix (the sixth pins existing behaviour): +64 MB, −64 MB,
admission of 256 MB, no admin action, 96 MB after the close of a refused reservation.
Mutants, each run against both classes:
close()releasingconfiguredCacheSizeinstead of the reserved size(the refused-reservation case red, nothing else), admission against
computeSize(config)(the admission case),setAdminActionRequireddropped (the restart case), and the old release byconfig(grow, shrink and the refusedreservation). Round 1, on master
0e039c6473, one JVM per run: the admission of the first commit(
newSize <= reservedCacheSize),reservedCacheSize→configuredCacheSizein the admission, the short circuitdropped,
newCacheSize = cfg.getDBCacheSize(), the opened-with baseline moved after the note, and the open guarddropped - each red on exactly its own case(s) in both classes. On the round head:
PDBStorageTest25/25,JEStorageTest22/22 (with the replay cases of #1065),FailedBackendOpenTest8/8,BackendConfigManagerTestCase11/11. Round 2, on master
e333af0c8f, one JVM per run: thereservedCacheSizeoperand of the admission'smaxdropped (
IllegalArgumentExceptionfrom a negativetryAcquire),!=→>in the restart note, andcomputeSizeor the admission reading thememQuotafield instead of the server context's quota (aNullPointerExceptionbefore the open) - each red on exactly its own case in both classes. On the round head:PDBStorageTest27/27,JEStorageTest24/24 (reactor,-Pprecommit verify).Regression set (one JVM per class, the fixed storages first on the classpath):
FailedBackendOpenTest,PDBTestCase,EncryptedPDBTestCase,JETestCase,EncryptedJETestCase,ReplayedConfigChangeTest,OnDiskMergeImporterTest,PersistentCompressedSchemaTest,DN2IDTest,StateTest,ID2EntryTest,ID2ChildrenCountTest,BulkCursorTest,DefaultIndexTest,ImportLDIFTestCase,RebuildIndexTestCase,VerifyIndexTestCase,BackendConfigManagerTestCase- 240 tests, 0 failures (FailedBackendOpenTestandPDBTestCasere-run after a collision on the admin port 65534 with another JVM on the machine).Not in this PR
ConfigurableEnvironment.validateDbCacheSizetookdb-cache-sizefrom the server's quota as aprobe and never gave it back; fixed on master by [#1067] Ask the memory quota whether an explicit db-cache-size fits instead of taking it #1070.
db-checkpointer-wakeup-interval) that are neither applied livenor marked as needing a restart.